#include "vg/base.h"
#include <map>
#include <set>

using namespace std;
using namespace anip;

class vg::VgFrameGroup::Renderer : public GraphicsRenderer
{
private:
	VgFrameGroup& _fg;
	map<Primitive*, GraphicsRenderer*> _renderers;
	GraphicsRenderer& getRenderer(Primitive& fg);

public:
	Renderer(VgFrameGroup& fg) :
		_fg(fg) {}
	~Renderer();

	GraphicObject& graphicObject() const override { return _fg; }

	void activate() override;
	void deactivate() override;
	void setFrame(float n) override;
	void setPresentationFrame(double realTime) override;
	void render(GraphicsRenderContext& cxt) override;
	void update() override;
};

void vg::VgFrameGroup::Renderer::update()
{
	set<Primitive*> ps(_fg.primitives.begin(), _fg.primitives.end());
	for (auto p : ps)
	{
		if (_renderers.find(p) == _renderers.end())
		{
			GraphicsRenderer* r = p->createRenderer();
			_renderers.insert({ p, r });
		}
	}
	
	map<Primitive*, GraphicsRenderer*> rcopy(_renderers);
	for (auto p : _renderers)
	{
		if (ps.find(p.first) == ps.end())
		{
			delete p.second;
			rcopy.erase(p.first);
		}
		else if (p.first->version() > p.second->version())
			p.second->update();
	}
	_renderers = rcopy;
}

GraphicsRenderer& vg::VgFrameGroup::Renderer::getRenderer(Primitive& e)
{
	if (_renderers.find(&e) == _renderers.end())
	{
		GraphicsRenderer* r = e.createRenderer();
		_renderers.insert({ &e, r });
		return *r;
	}
	return *_renderers[&e];
}

void vg::VgFrameGroup::Renderer::setFrame(float t)
{
	GraphicsRenderer::setFrame(t);
	for (auto p : _fg.primitives)
		getRenderer(*p).setFrame(t);
}

void vg::VgFrameGroup::Renderer::activate()
{
	// update renderers when activating
	GraphicsRenderer::activate();
	for (auto p : _fg.primitives)
		getRenderer(*p).activate();
}

void vg::VgFrameGroup::Renderer::deactivate()
{
	GraphicsRenderer::deactivate();
	for (auto p : _renderers)
		p.second->deactivate();
}

void vg::VgFrameGroup::Renderer::setPresentationFrame(double realTime)
{
	GraphicsRenderer::setPresentationFrame(realTime);
	for (auto p : _renderers)
		p.second->setPresentationFrame(realTime);
}

void vg::VgFrameGroup::Renderer::render(GraphicsRenderContext& cxt)
{
	for (auto p : _fg.primitives)
	{
		assert(_renderers.find(p) != _renderers.end());
		_renderers[p]->render(cxt);
	}
}

anip::vg::VgFrameGroup::~VgFrameGroup()
{
	for (auto p : primitives)
		delete p;
}

GraphicsRenderer* vg::VgFrameGroup::createRenderer()
{
	return new Renderer(*this);
}

serializer_implementation(vg::VgFrameGroup)(FrameGroup& obj, ostream& out)
{
	auto& vfg = (VgFrameGroup&)obj;
	binaryWrite<size_t>(vfg.primitives.size(), out);
	for (auto p : vfg.primitives)
		serialize<Primitive>(*p, out);
}

deserializer_implementation(vg::VgFrameGroup)(istream& in)
{
	size_t n;
	binaryRead(n, in);
	auto vfg = new VgFrameGroup();
	for (; n > 0; n--)
	{
		auto p = deserialize<Primitive>(in);
		vfg->primitives.push_back(p);
	}
	return vfg;
}